/**
 * TabVD is a Virtual Desktop Client/Server designed specifically for connecting
 * from Tablet like devices.
 *
 * Copyright (C) 2011 Subhabrata Ghosh
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * Entities.java
 *
 *  Created on: Jul 23, 2011
 *      Author: subhagho
 */
package net.langene.tabvd.core.db;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Date;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import net.langene.tabvd.core.DateUtils;
import net.langene.tabvd.core.Global;
import net.langene.tabvd.core.XMLHelper;
import net.langene.tabvd.core.db.Schema.Table;

/**
 * @author subhagho
 * 
 */
public class Entities {
	/**
	 * Load the entities from XML.
	 * 
	 * net.langene.tabvd.core.db.Entities
	 * 
	 * @param nodes
	 * @return
	 * @throws Exception
	 */
	public static List<EntityBase> loadEntities(XMLHelper helper, String xpath)
			throws Exception {
		List<EntityBase> entities = new LinkedList<Entities.EntityBase>();
		NodeList nodes = helper.find(xpath);
		if (nodes == null || nodes.getLength() <= 0)
			throw new Exception("No setup data foundin file.");
		for (int ii = 0; ii < nodes.getLength(); ii++) {
			Element tabelem = (Element) nodes.item(ii);
			String tabname = tabelem.getAttribute("name");
			if (tabname == null || tabname.isEmpty())
				throw new Exception(
						"Invalid Table record : Missing table name.");
			loadTableData(tabname, tabelem, helper);
		}
		return entities;
	}

	private static void loadTableData(String name, Node tabnode,
			XMLHelper helper) throws Exception {
		NodeList records = helper.find(tabnode, "./record");
		if (records == null || records.getLength() <= 0)
			throw new Exception("No records found for table [" + name + "]");
		if (name.compareToIgnoreCase("AuditType") == 0) {

		} else if (name.compareToIgnoreCase("User") == 0) {

		} else if (name.compareToIgnoreCase("Role") == 0) {

		} else if (name.compareToIgnoreCase("Version") == 0) {

		}
		throw new Exception("Table [" + name + "] not supported for XML load.");
	}

	public static enum EntityState {
		New, Updated, Deleted, NoChange
	}

	public static abstract class EntityBase {
		protected EntityState state = EntityState.NoChange;

		public abstract void save(Connection conn) throws Exception;

		public abstract void delete(Connection conn) throws Exception;

	}

	public static enum AuditSeverity {
		High, Medium, Low
	}

	public static class Audit extends EntityBase {
		private AuditType type;
		private Date timestamp;
		private String user;
		private String message;

		/**
		 * @return the type
		 */
		public AuditType getType() {
			return type;
		}

		/**
		 * @param type
		 *            the type to set
		 */
		public void setType(AuditType type) {
			this.type = type;
		}

		/**
		 * @return the timestamp
		 */
		public Date getTimestamp() {
			return timestamp;
		}

		/**
		 * @param timestamp
		 *            the timestamp to set
		 */
		public void setTimestamp(Date timestamp) {
			this.timestamp = timestamp;
		}

		/**
		 * @return the user
		 */
		public String getUser() {
			return user;
		}

		/**
		 * @param user
		 *            the user to set
		 */
		public void setUser(String user) {
			this.user = user;
		}

		/**
		 * @return the message
		 */
		public String getMessage() {
			return message;
		}

		/**
		 * @param message
		 *            the message to set
		 */
		public void setMessage(String message) {
			this.message = message;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#save(java.sql.Connection
		 * )
		 */
		@Override
		public void save(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#delete(java.sql.Connection
		 * )
		 */
		@Override
		public void delete(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		public static Audit createNew() {
			Audit audit = new Audit();
			audit.state = EntityState.New;
			return audit;
		}
	}

	public static class AuditType extends EntityBase {
		private String id;
		private String name;
		private String description;
		private AuditSeverity severity;
		private String createdby;
		private Date createddate;

		public AuditType(String id) {
			this.id = id;
		}

		/**
		 * @return the name
		 */
		public String getName() {
			return name;
		}

		/**
		 * @param name
		 *            the name to set
		 */
		public void setName(String name) {
			this.name = name;
		}

		/**
		 * @return the description
		 */
		public String getDescription() {
			return description;
		}

		/**
		 * @param description
		 *            the description to set
		 */
		public void setDescription(String description) {
			this.description = description;
		}

		/**
		 * @return the severity
		 */
		public AuditSeverity getSeverity() {
			return severity;
		}

		/**
		 * net.langene.tabvd.core.db.AuditType
		 * 
		 * @param severity
		 */
		public void setSeverity(String severity) {
			this.severity = AuditSeverity.valueOf(severity);
		}

		/**
		 * @param severity
		 *            the severity to set
		 */
		public void setSeverity(AuditSeverity severity) {
			this.severity = severity;
		}

		/**
		 * @return the createdby
		 */
		public String getCreatedby() {
			return createdby;
		}

		/**
		 * @param createdby
		 *            the createdby to set
		 */
		public void setCreatedby(String createdby) {
			this.createdby = createdby;
		}

		/**
		 * @return the id
		 */
		public String getId() {
			return id;
		}

		/**
		 * @return the createddate
		 */
		public Date getCreateddate() {
			return createddate;
		}

		/**
		 * @param createddate
		 *            the createddate to set
		 */
		public void setCreateddate(Date createddate) {
			this.createddate = createddate;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#save(java.sql.Connection
		 * )
		 */
		@Override
		public void save(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#delete(java.sql.Connection
		 * )
		 */
		@Override
		public void delete(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		public static AuditType createNew(String id) {
			AuditType type = new AuditType(id);
			type.state = EntityState.New;
			type.createddate = DateUtils.now();
			return type;
		}
	}

	public static class ProfileParameter extends EntityBase {
		private String id;
		private String name;
		private String description;
		private String value;
		private Date updateddate;

		public ProfileParameter(String id, String name) {
			this.id = id;
			this.name = name;
		}

		/**
		 * @return the name
		 */
		public String getName() {
			return name;
		}

		/**
		 * @return the description
		 */
		public String getDescription() {
			return description;
		}

		/**
		 * @param description
		 *            the description to set
		 */
		public void setDescription(String description) {
			this.description = description;
		}

		/**
		 * @return the value
		 */
		public String getValue() {
			return value;
		}

		/**
		 * @param value
		 *            the value to set
		 */
		public void setValue(String value) {
			this.value = value;
		}

		/**
		 * @return the id
		 */
		public String getId() {
			return id;
		}

		/**
		 * @return the updateddate
		 */
		public Date getUpdateddate() {
			return updateddate;
		}

		/**
		 * @param updateddate
		 *            the updateddate to set
		 */
		public void setUpdateddate(Date updateddate) {
			this.updateddate = updateddate;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#save(java.sql.Connection
		 * )
		 */
		@Override
		public void save(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#delete(java.sql.Connection
		 * )
		 */
		@Override
		public void delete(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		public static ProfileParameter createNew(String id, String name) {
			ProfileParameter param = new ProfileParameter(id, name);
			param.state = EntityState.New;
			return param;
		}
	}

	public static class Profile extends EntityBase {
		private String id;
		private String name;
		private String description;
		private User owner;
		private Date createddate;
		private Hashtable<String, ProfileParameter> parameters = null;

		public Profile(String id) {
			this.id = id;
		}

		public ProfileParameter getParameter(String name) {
			if (parameters != null && parameters.containsKey(name))
				return parameters.get(name);
			return null;
		}

		public void addParameter(ProfileParameter param) {
			if (parameters == null)
				parameters = new Hashtable<String, Entities.ProfileParameter>();
			if (parameters.containsKey(param.getName())) {
				parameters.remove(param.getName());
			}
			parameters.put(param.getName(), param);
		}

		/**
		 * @return the name
		 */
		public String getName() {
			return name;
		}

		/**
		 * @param name
		 *            the name to set
		 */
		public void setName(String name) {
			this.name = name;
		}

		/**
		 * @return the description
		 */
		public String getDescription() {
			return description;
		}

		/**
		 * @param description
		 *            the description to set
		 */
		public void setDescription(String description) {
			this.description = description;
		}

		/**
		 * @return the owner
		 */
		public User getOwner() {
			return owner;
		}

		/**
		 * @param owner
		 *            the owner to set
		 */
		public void setOwner(User owner) {
			this.owner = owner;
		}

		/**
		 * @return the id
		 */
		public String getId() {
			return id;
		}

		/**
		 * @return the createddate
		 */
		public Date getCreateddate() {
			return createddate;
		}

		/**
		 * @param createddate
		 *            the createddate to set
		 */
		public void setCreateddate(Date createddate) {
			this.createddate = createddate;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#save(java.sql.Connection
		 * )
		 */
		@Override
		public void save(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#delete(java.sql.Connection
		 * )
		 */
		@Override
		public void delete(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		public Profile createNew(String id) {
			Profile profile = new Profile(id);
			profile.state = EntityState.New;
			profile.createddate = DateUtils.now();
			return profile;
		}
	}

	public static final class User extends EntityBase {
		private String id;
		private String name;
		private String password;
		private Role role;
		private String createdby;
		private Date createddate;
		private Date lastlogin;
		private int failedlogins;

		public User(String id) {
			this.id = id;
		}

		/**
		 * @return the name
		 */
		public String getName() {
			return name;
		}

		/**
		 * @param name
		 *            the name to set
		 */
		public void setName(String name) {
			this.name = name;
		}

		/**
		 * @return the password
		 */
		public String getPassword() {
			return password;
		}

		/**
		 * @param password
		 *            the password to set
		 */
		public void setPassword(String password) {
			this.password = password;
		}

		/**
		 * @return the role
		 */
		public Role getRole() {
			return role;
		}

		/**
		 * @param role
		 *            the role to set
		 */
		public void setRole(Role role) {
			this.role = role;
		}

		/**
		 * @return the createdby
		 */
		public String getCreatedby() {
			return createdby;
		}

		/**
		 * @param createdby
		 *            the createdby to set
		 */
		public void setCreatedby(String createdby) {
			this.createdby = createdby;
		}

		/**
		 * @return the lastlogin
		 */
		public Date getLastlogin() {
			return lastlogin;
		}

		/**
		 * @param lastlogin
		 *            the lastlogin to set
		 */
		public void setLastlogin(Date lastlogin) {
			this.lastlogin = lastlogin;
		}

		/**
		 * @return the failedlogins
		 */
		public int getFailedlogins() {
			return failedlogins;
		}

		/**
		 * @param failedlogins
		 *            the failedlogins to set
		 */
		public void setFailedlogins(int failedlogins) {
			this.failedlogins = failedlogins;
		}

		/**
		 * @return the id
		 */
		public String getId() {
			return id;
		}

		/**
		 * @return the createddate
		 */
		public Date getCreateddate() {
			return createddate;
		}

		/**
		 * @param createddate
		 *            the createddate to set
		 */
		public void setCreateddate(Date createddate) {
			this.createddate = createddate;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#save(java.sql.Connection
		 * )
		 */
		@Override
		public void save(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#delete(java.sql.Connection
		 * )
		 */
		@Override
		public void delete(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		public static User createNew(String id) {
			User user = new User(id);
			user.state = EntityState.New;
			user.createddate = DateUtils.now();
			return user;
		}
	}

	public static final class Role extends EntityBase {
		private String id;
		private String name;
		private String description;
		private String createdby;
		private Date createddate;

		public Role(String id) {
			this.id = id;
		}

		/**
		 * @return the id
		 */
		public String getId() {
			return id;
		}

		/**
		 * @return the name
		 */
		public String getName() {
			return name;
		}

		/**
		 * @param name
		 *            the name to set
		 */
		public void setName(String name) {
			this.name = name;
		}

		/**
		 * @return the description
		 */
		public String getDescription() {
			return description;
		}

		/**
		 * @param description
		 *            the description to set
		 */
		public void setDescription(String description) {
			this.description = description;
		}

		/**
		 * @return the createdby
		 */
		public String getCreatedby() {
			return createdby;
		}

		/**
		 * @param createdby
		 *            the createdby to set
		 */
		public void setCreatedby(String createdby) {
			this.createdby = createdby;
		}

		/**
		 * @return the createddate
		 */
		public Date getCreateddate() {
			return createddate;
		}

		/**
		 * @param createddate
		 *            the createddate to set
		 */
		public void setCreateddate(Date createddate) {
			this.createddate = createddate;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#save(java.sql.Connection
		 * )
		 */
		@Override
		public void save(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#delete(java.sql.Connection
		 * )
		 */
		@Override
		public void delete(Connection conn) throws Exception {
			// TODO Auto-generated method stub

		}

		public static Role createNew(String id) {
			Role role = new Role(id);
			role.state = EntityState.New;
			role.createddate = DateUtils.now();
			return role;
		}
	}

	public static final class Version extends EntityBase {
		private String id;
		private Date timestamp;

		/**
		 * @return the id
		 */
		public String getId() {
			return id;
		}

		/**
		 * @return the timestamp
		 */
		public Date getTimestamp() {
			return timestamp;
		}

		public Version(String id) {
			this.id = id;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#save(java.sql.Connection
		 * )
		 */
		@Override
		public void save(Connection conn) throws Exception {
			if (this.state != EntityState.New)
				return;
			Table table = Global.schema().Tables.get("VERSION");
			String insertsql = table.getInsertSql();

			PreparedStatement pstmnt = conn.prepareStatement(insertsql);
			table.getColumn("Id").setPreparedParameter(pstmnt, 1, this.id);
			table.getColumn("InstallDate").setPreparedParameter(pstmnt, 2,
					this.timestamp);
			pstmnt.executeUpdate();
			pstmnt.close();
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * net.langene.tabvd.core.db.Entities.EntityBase#delete(java.sql.Connection
		 * )
		 */
		@Override
		public void delete(Connection conn) throws Exception {
			throw new Exception("Cannot delete Version record.");
		}

		public static Version createNew(String id) {
			Version version = new Version(id);
			version.state = EntityState.New;
			version.timestamp = DateUtils.now();
			return version;
		}
	}
}
